<script lang="ts" setup name="MapChoose">
import axios from 'axios'
import L from 'leaflet'
import type { AutocompleteFetchSuggestionsCallback as callbackfn } from 'element-plus'
import { useThemeStore } from '@/stores/modules/theme'
import type { MapLocation, TianDiTu } from './interface'

const emit = defineEmits(['confirm'])
const themeStore = useThemeStore()

// const GaoDeKey = '75637e28b33dc69cab8b79ed244a785e' //高德-阳洋出行
const GaoDeKey = 'f432bde5badb995e8460f8a11147d6ef' //高德-个人开发
const TianDiTuKey = 'e24f4fc9a96afd500faa9ac9232eb86a' //天地图-个人
const mapRef = ref()
const dialogVisible = ref(false)
const mapLocation = reactive<MapLocation>({
  name: '',
  address: '',
  lng: 0,
  lat: 0
})
let marker: L.Marker | null = null
const mapType = computed(() => themeStore.themeConfig.mapType)

const show = (val: MapLocation | null) => {
  dialogVisible.value = true
  nextTick(() => {
    mapRef.value.loadMap()
    mapRef.value.map.on('click', mapClick)
    if (val && val.lng && val.lat) {
      mapLocation.lng = val.lng
      mapLocation.lat = val.lat
      mapLocation.address = val.address || ''
      mapLocation.name = val.name || ''
      drawMarker()
    } else {
      marker && marker.remove()
      marker = null
    }
  })
}

const keyword = ref('')
/** 搜索地址 */
const searchAddress = async (queryString: string, cb: callbackfn) => {
  const currentLocation = mapRef.value.map.getCenter()
  switch (mapType.value) {
    case 'GaoDe':
      const { data } = await axios.get('https://restapi.amap.com/v3/assistant/inputtips', {
        params: {
          key: GaoDeKey,
          keywords: queryString,
          location: currentLocation.lng.toFixed(6) + ',' + currentLocation.lat.toFixed(6)
        }
      })
      cb(data.tips)
      break
    case 'TianDiTu':
      const TianDiTuParams = {
        mapBound: '-180,-90,180,90',
        level: 11,
        queryType: 7, //1=普通搜索 2=视野内搜索
        start: 0,
        count: 10,
        show: 2
      }
      const res = await TianDiTuSearch({ ...TianDiTuParams, keyWord: queryString })
      cb(res)
      break
    default:
      cb([])
  }
}
/** 天地图搜索 */
const TianDiTuSearch = async (params: TianDiTu.SearchPostStrParams): Promise<MapLocation[]> => {
  let result: MapLocation[] = []
  const { data } = await axios.get('http://api.tianditu.gov.cn/v2/search', {
    params: {
      postStr: JSON.stringify(params),
      type: 'query',
      tk: TianDiTuKey
    }
  })
  if (data.pois) {
    result = TianDiTuFormat(data.pois)
  } else if (data.statistics) {
    const { statistics } = data
    if (statistics.priorityCitys) {
      const { priorityCitys } = statistics
      priorityCitys.length &&
        (result = await TianDiTuSearch({ ...params, specify: priorityCitys[0].adminName }))
    } else if (statistics.allAdmins) {
      const { allAdmins } = statistics
      allAdmins.length &&
        (result = await TianDiTuSearch({ ...params, specify: allAdmins[0].adminName }))
    }
  }
  return result
}
/** 天地图pois格式化 */
const TianDiTuFormat = (pois: TianDiTu.ResponsePoisItem[]) => {
  return pois.map((item) => {
    const { province, city, county, address, name, lonlat } = item
    const areaStr = province + city + county
    const [lng, lat] = lonlat.split(',')
    return {
      name,
      address: address.indexOf(areaStr) > -1 ? address : areaStr + address,
      lng: +lng,
      lat: +lat
    }
  })
}
/** 选择搜索地址 */
const selectAddress = (item: MapLocation) => {
  keyword.value = item.name
  mapLocation.lng = item.lng
  mapLocation.lat = item.lat
  mapLocation.address = item.address
  mapLocation.name = item.name
  drawMarker()
}
/** 地图点击事件（逆地理编码） */
const mapClick = async (e: L.LeafletMouseEvent) => {
  const { lat, lng } = e.latlng
  switch (mapType.value) {
    case 'GaoDe':
      const { data } = await axios.get('https://restapi.amap.com/v3/geocode/regeo', {
        params: {
          key: GaoDeKey,
          location: lng.toFixed(6) + ',' + lat.toFixed(6),
          extensions: 'all'
        }
      })
      if (data.info !== 'OK') {
        ElMessage.error('获取地址失败')
        return
      }
      mapLocation.lng = lng
      mapLocation.lat = lat
      mapLocation.address = data.regeocode.formatted_address
      mapLocation.name = data.regeocode.addressComponent.building.name.length
        ? data.regeocode.addressComponent.building.name
        : data.regeocode.pois.length
          ? data.regeocode.pois[0].name
          : data.regeocode.formatted_address
      drawMarker()
      break
    case 'TianDiTu':
      const res: any = await axios.get('http://api.tianditu.gov.cn/geocoder', {
        params: {
          postStr: JSON.stringify({
            lon: lng,
            lat,
            ver: 1
          }),
          type: 'geocode',
          tk: TianDiTuKey
        }
      })
      if (res.data.msg !== 'ok' || !res.data.result || !res.data.result.formatted_address) {
        ElMessage.error('获取地址失败')
        return
      }
      const { formatted_address, addressComponent } = res.data.result
      mapLocation.lng = lng
      mapLocation.lat = lat
      mapLocation.address = formatted_address
      mapLocation.name = addressComponent.poi
      drawMarker()
      break
    default:
      ElMessage.error('暂不支持该地图类型')
      break
  }
}

/** 绘制标记 */
const drawMarker = () => {
  const { lng, lat, address, name } = mapLocation
  if (marker)
    marker.setLatLng([lat, lng]).setPopupContent(getPopupContent(name, address)).openPopup()
  else {
    marker = L.marker([lat, lng])
    marker
      .addTo(mapRef.value.map)
      .bindPopup(getPopupContent(name, address), { closeButton: false })
      .openPopup()
    // mapRef.value.map.addLayer(marker)
  }
  mapRef.value.map.setView([lat, lng], 16)
}
/** 地图标记弹出框内容 */
const getPopupContent = (name: string, address: string) => {
  return `<div class="text-14 m-b-10">${name}</div><div class=" text-#999">${address}</div>`
}
/** 点击确定 */
const handleConfirm = () => {
  if (mapLocation.lng === 0 || mapLocation.lat === 0) {
    ElMessage.error('请选择地址')
    return
  }
  emit('confirm', mapLocation)
  dialogVisible.value = false
}

defineExpose({
  show
})
</script>

<template>
  <el-dialog v-model="dialogVisible" title="地图选点" width="720">
    <div class="w-688 h-400 bg-#f7f7f7 rounded-5 overflow-hidden relative">
      <Map ref="mapRef" :isAutoLoad="false" />

      <el-autocomplete
        v-model="keyword"
        :fetch-suggestions="searchAddress"
        :trigger-on-focus="false"
        clearable
        placeholder="输入(城市)关键字搜索"
        @select="selectAddress"
        style="width: 300px"
      >
        <template #default="{ item }">
          <div class="flex w-260">
            <span class="text-overflow" :title="item.name">{{ item.name }}</span>
            <span class="text-12 text-#999 m-l-10 text-overflow flex-1" :title="item.address">{{
              item.address
            }}</span>
          </div>
        </template>
      </el-autocomplete>
    </div>
    <template #footer>
      <el-button @click="dialogVisible = false">取消</el-button>
      <el-button type="primary" @click="handleConfirm">确定</el-button>
    </template>
  </el-dialog>
</template>

<style lang="scss" scoped>
:deep(.el-autocomplete) {
  position: absolute;
  left: 10px;
  top: 10px;
  z-index: 999;
}
</style>
